﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
//using System.Windows.Shapes;

using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Symbols;
using ESRI.ArcGIS.Client.Tasks;
using ESRI.ArcGIS.Client.Toolkit;
using ESRI.ArcGIS.Client.FeatureService;

using Microsoft.Surface.Presentation.Controls;

using GISforTT_API;

namespace GISforTT_API
{
    /// <summary>
    /// This class is the container which holds the ArcGIS map.
    /// It defines the contact events needed to scale and pan the map. 
    /// It reflects these changes back onto the contained map.    
    /// </summary>
    public partial class ArcGisMap : UserControl
    {
        private Draw MyDrawObject = null;
        private Symbol _activeSymbol = null;

        private GhostFrame linkedGhostFrame = null;

        private MapLayersManager.MapLayerAddedDelegate addDelegate;
        private MapLayersManager.MapLayerDeletedDelegate deleteDelegate;
        private MapLayersManager.AnnotationLayersUpdatedDelegate annotationUpdateDelegate;


        #region Map Properties

        /// <summary>
        /// Ghost frame
        /// </summary>
        public GhostFrame LinkedGhostFrame
        {
            get
            {
                return linkedGhostFrame;
            }

            set
            {
                linkedGhostFrame = value;
            }
        }

        /// <summary>
        /// Width of the map
        /// </summary>
        public double MapWidth
        {
            get
            {
                return MyMap.Width;
            }

            set
            {
                MyMap.Width = value;
            }
        }

        /// <summary>
        /// Height of the map
        /// </summary>
        public double MapHeight
        {
            get
            {
                return MyMap.Height;
            }

            set
            {
                MyMap.Height = value;
            }
        }

        /// <summary>
        /// The initial extent of the map 
        /// </summary>
        private Envelope initialExtent;
        public Envelope InitialExtent
        {
            get
            {
                return initialExtent;
            }

            set
            {
                initialExtent = value;
            }
        }

        /// <summary>
        /// Wether the layers list should be visible on the map
        /// </summary>
        private bool showLayersList = false;
        public bool ShowLayersList
        {
            get
            {
                return showLayersList;
            }

            set
            {
                showLayersList = value;
                if (showLayersList)
                {
                    LayersListBorder.Visibility = Visibility.Visible;
                    LayersList.Visibility = Visibility.Visible;
                }
                else
                {
                    LayersListBorder.Visibility = Visibility.Hidden;
                    LayersList.Visibility = Visibility.Hidden;
                }
            }
        }

        /// <summary>
        /// Returns the center of the extent of the map
        /// </summary>
        public Point Center
        {
            get
            {
                MapPoint centerPoint = MyMap.Extent.GetCenter();
                return MyMap.MapToScreen(centerPoint);
            }
        }

        /// <summary>
        /// Returns the actual Map object 
        /// contained in this class.
        /// </summary>
        /// <returns>The actual Map object represented by this class</returns>
        public Map Map
        {
            get
            {
                return MyMap;
            }
            set
            {
                MyMap = value;
            }
        }

        /// <summary>
        /// For Testing: Return the URL of the Map
        /// </summary>
        public string MapURL
        {
            get
            {
                ArcGISTiledMapServiceLayer arcgisLayer = MyMap.Layers["StreetMap"] as ArcGISTiledMapServiceLayer;
                return arcgisLayer.Url;
            }
        }

        /// <summary>
        /// For Testing: Return the extent of the map
        /// </summary>
        public Envelope Extent
        {
            get
            {
                return MyMap.Extent;
            }
        }

        /// <summary>
        /// For Testing: Return the zoom factor of the map
        /// </summary>
        public double ZoomFactor
        {
            get
            {
                return MyMap.ZoomFactor;
            }
        }

        private bool canPan = true;
        public bool CanPan
        {
            get
            {
                return canPan;
            }

            set
            {
                canPan = value;
            }
        }

        private bool canZoom = true;
        public bool CanZoom
        {
            get
            {
                return canZoom;
            }

            set
            {
                canZoom = value;
            }
        }

        private bool isBgMap = false;
        public bool isBackgroundMap
        {
            get
            {
                return isBgMap;
            }

            set
            {
                isBgMap = value;
                InitializeMapLayers();
                //the background map gets to have the original set of map layers created by MapLayersManager
                //other maps get cloned copies of these layers. each layer can only belong to one map at a time.
                //since we cannot know which set of layers to initialize until this property is set, initialization happens here now.
            }
        }

        public Grid MainGrid
        {
            get { return LayoutRoot; }
        }

        # endregion

        #region Constructor and Initializations
        
        /// <summary>
        /// Default constructor. The ArcGisMap object is a wrapper around the ArcGIS map object providing more features.
        /// </summary>
        public ArcGisMap()
        {
            
            InitializeComponent();

            initialExtent = MyMap.Extent;

            //InitializeMapLayers(); // moved to isbgMap property assignment

            //MyMap.GotTouchCapture += new EventHandler<TouchEventArgs>(MyMap_GotTouchCapture);
            //MyMap.LostTouchCapture += new EventHandler<TouchEventArgs>(MyMap_LostTouchCapture);

            InitializeGraphics();

            // Disable the unsightly magnifying glass on edit, added in API v 2.1
            Editor.SetIsTouchMagnifierEnabled(MyMap, false);

            // Listen for new map features added to other map frames.
            annotationUpdateDelegate = new MapLayersManager.AnnotationLayersUpdatedDelegate(RefreshAnnotationLayers);
            MapLayersManager.Instance.AnnotationLayersUpdated += annotationUpdateDelegate;
        }

        public void initializeCloneDelegates()
        {
            addDelegate = new MapLayersManager.MapLayerAddedDelegate(AddMapLayer);
            deleteDelegate = new MapLayersManager.MapLayerDeletedDelegate(RemoveMapLayer);
            

            MapLayersManager.Instance.MapLayerAdded += addDelegate;
            MapLayersManager.Instance.MapLayerDeleted += deleteDelegate;
        }

        void MyMap_LostTouchCapture(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void InitializeMapLayers()
        {
         /*   if (isBgMap)
            { // TODO call to MapLayersManager for main map layers.
            }
            else
            {
                LayerCollection layers = MapLayersManager.Instance.MapLayers;

                foreach (Layer layer in layers)
                {
                    Layer clone = MapLayersManager.Instance.CloneLayer(layer);
                    if (clone != null)
                        AddMapLayer(clone);
                }
            }*/


            if (isBgMap)
            {
                MyMap.Layers = MapLayersManager.Instance.MapLayers;
            }
            else
            {
                MyMap.Layers = MapLayersManager.Instance.CloneLayers;
                initializeCloneDelegates();
            }

        }
/*
        private void InitializeDefaultMapLayers()
        {
            ArcGISTiledMapServiceLayer streetLayer = new ArcGISTiledMapServiceLayer();

            streetLayer.Initialized += (evtsender, args) =>
                {
                    MyMap.ZoomTo(initialExtent);
                };

            streetLayer.ID = "StreetMap";
            streetLayer.Opacity = 1;
            streetLayer.Url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";

            ArcGISTiledMapServiceLayer imageryLayer = new ArcGISTiledMapServiceLayer();

            imageryLayer.Initialized += (evtsender, args) =>
            {
                MyMap.ZoomTo(initialExtent);
            };

            imageryLayer.ID = "Imagery";
            imageryLayer.Opacity = 1;
            imageryLayer.Visible = false;
            imageryLayer.Url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer";

            ArcGISTiledMapServiceLayer topoLayer = new ArcGISTiledMapServiceLayer();

            topoLayer.Initialized += (evtsender, args) =>
            {
                MyMap.ZoomTo(initialExtent);
            };

            topoLayer.ID = "ShadedRelief";
            topoLayer.Opacity = 1;
            topoLayer.Visible = false;
            topoLayer.Url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_ShadedRelief_World_2D/MapServer";
            
            MyMap.Layers.Add(streetLayer);
            MyMap.Layers.Add(imageryLayer);
            MyMap.Layers.Add(topoLayer);
        }
*/
        /// <summary>
        /// This method is to be used only when this object is used as the background map in the application
        /// </summary>
        /// <param name="isBg">True if this map object is a background map</param>
        public void setIsABackgroundMap(bool isBg)
        {
            isBgMap = isBg;
        }

        /// <summary>
        /// Returns whether this object represnts a background map
        /// </summary>
        /// <returns></returns>
        public bool isABackgroundMap()
        {
            return isBgMap;
        }

        /// <summary>
        /// For testing purposes. Returns true if the map draw object is created and thus annotations are enabled
        /// </summary>
        /// <returns></returns>
        public bool isDrawObjectCreated()
        {
            if (MyDrawObject != null)   return true;

            return false;
        }

        #endregion

        #region Map Event Handlers

        /// <summary>
        /// Scaling the map
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.PreviousSize.Height == 0)
                return;

            // Resize the map grid
            MapWidth = e.NewSize.Width;
            MapHeight = e.NewSize.Height;

            ReloadMap();
        }

        private void MyMap_Initialized(object sender, EventArgs e)
        {
            MyMap.ZoomTo(initialExtent);
            if (linkedGhostFrame != null)
            {
                linkedGhostFrame.UpdatePosition(Extent);
            }
        }

        private void MyMap_ExtentChanged(object sender, ExtentEventArgs e)
        {
            if (e.OldExtent == null)
            {
                initialExtent = e.NewExtent;
            }
            if (linkedGhostFrame != null)
            {
                linkedGhostFrame.UpdatePosition(Extent);
            }
        }


        private void MyMap_ExtentChanging(object sender, ESRI.ArcGIS.Client.ExtentEventArgs e)
        {
            if ((!canPan || !canZoom) && !ExtentsApproximatelyEqual(e.NewExtent, initialExtent)) 
                // Proceed only if we are changing the extent, to prevent infinite recursion 
            {
                MyMap.Extent = initialExtent; // this call will trigger another MyMap_ExtentChanging
            }
            if (linkedGhostFrame != null)
            {
                linkedGhostFrame.UpdatePosition(Extent);
            }
        }

        //Envelope.Equals does not appear to work, necessitating this function: 
        static private bool ExtentsApproximatelyEqual(Envelope one, Envelope two)
        {
            double TOLERANCE = 0.000001;
            if  (
                ((one.XMax >= two.XMax - TOLERANCE) && (one.XMax <= two.XMax + TOLERANCE)) &&
                ((one.YMax >= two.YMax - TOLERANCE) && (one.YMax <= two.YMax + TOLERANCE)) &&
                ((one.XMin >= two.XMin - TOLERANCE) && (one.XMin <= two.XMin + TOLERANCE)) &&
                ((one.YMin >= two.YMin - TOLERANCE) && (one.YMin <= two.YMin + TOLERANCE))
                )
            {
                return true;
            }
            else
                return false;
        }

        private void MyMap_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (!canPan || !canZoom)
                e.Handled = true;
        }

        private void MyMap_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) // this is never attached to events anywhere ... 
        {
            if (!canPan || !canZoom)
            {
                MyMap.ExtentChanging += new EventHandler<ESRI.ArcGIS.Client.ExtentEventArgs>(MyMap_ExtentChanging);
                initialExtent = MyMap.Extent;
                e.Handled = true;
            }
        }

        private void MyMap_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {

            if (!canPan || !canZoom)
            {
                MyMap.ExtentChanging -= MyMap_ExtentChanging;
                e.Handled = true;

            }
        }

        private void MyMap_TouchDown(object sender, TouchEventArgs e)
        {
            Map captured = sender as Map;

            if (isBgMap)
            {
                MyMap.IsManipulationEnabled = false; // manipulation needs to be off, so that mainmap touches are promoted to clicks, and trigger clickable map graphics
            }
            else
            {
                captured.IsManipulationEnabled = true;

                e.TouchDevice.Capture(captured);
                
            }
            
        }

        private void MyMap_TouchUp(object sender, TouchEventArgs e)
        {
            Map captured = sender as Map;
            captured.IsManipulationEnabled = false;
            if (e.TouchDevice.Captured == captured)
            {
                captured.ReleaseAllTouchCaptures();
                captured.ReleaseMouseCapture();
            }
        }



        # endregion

        #region ZoomingAndPanning
        
        /// <summary>
        /// Zoom in or out
        /// </summary>
        /// <param name="factor">zooming factor</param>
        public void Zoom(double factor)
        {
            // > 1 = zoom in
            // < 1 = zoom out
            if(!isMapInDrawMode())
                MyMap.Zoom(factor);
        }

        /// <summary>
        /// Zoom to a specific extent...
        /// Map animation will operate during the extent change. 
        /// </summary>
        /// <param name="geom">extent to which the map should zoom</param>
        public void ZoomTo(ESRI.ArcGIS.Client.Geometry.Geometry geom)
        {
            if (!isMapInDrawMode())
                MyMap.ZoomTo(geom);
        }


        /// <summary>
        /// Pan to a screen point
        /// PanTo: Pan to an extent that centers on the ESRI.ArcGIS.Client.Geometry instance passed to the method. 
        /// Map scale will not change. Map animation will operate during the operation.
        /// </summary>
        /// <param name="screenPoint">point to which the map will pan</param>
        public void PanTo(System.Windows.Point screenPoint)
        {
            if (!isMapInDrawMode())
                if (MyMap.Extent != null)
            {
                MapPoint mapPoint = MyMap.ScreenToMap(screenPoint);                                
                MyMap.PanTo(mapPoint);
            }

        }

        /// <summary>
        /// Set the extent from latitude and longitude.
        /// X values are longitudes and Y values are latitudes
        /// </summary>
        /// <param name="lat">latitude</param>
        /// <param name="lng">longitude</param>
        public void setExtentFromLtdLng(double lat, double lng)
        {
            if (!isMapInDrawMode())
            {
                double x1, y1, x2, y2;

                x1 = lng + 0.01;
                x2 = lng - 0.01;

                y1 = lat + 0.001;
                y2 = lat - 0.001;

                Envelope newExtent = new Envelope(x1, y1, x2, y2);
                MyMap.Extent = newExtent;
            }
        }

        /// <summary>
        /// Set the extent of the the map using an
        /// Evelope arugment such that the map will
        /// display the given area.
        /// </summary>
        /// <param name="input">The Envelope area to be shown</param>
        public void setExtentFromEnvelop(Envelope input)
        {
            if (!isMapInDrawMode())
            {
                if (MyMap.Extent == null)
                {
                    Envelope env = new Envelope(input.XMax, input.YMax, input.XMin, input.YMin);
                    MyMap.Extent = env;
                }
                else
                {
                    MyMap.Extent = input;
                }
            }
        }

        # endregion ZoomingAndPanning

        #region Annotations

        ///// <summary>
        ///// Used the change the visibility of the annotations toolbar
        ///// </summary>
        //public void ToggleAnnotationsToolbarVisibility()
        //{
        //    if (AnnotationsToolbar.Visibility == Visibility.Hidden)
        //        AnnotationsToolbar.Visibility = Visibility.Visible;
        //    else
        //        AnnotationsToolbar.Visibility = Visibility.Hidden;
        //}

        /// <summary>
        /// Initialize the graphics layer and draw object
        /// </summary>
        private void InitializeGraphics()
        {
            MyDrawObject = new Draw(MyMap)
            {
                LineSymbol = LayoutRoot.Resources["DrawLineSymbol"] as LineSymbol,
                FillSymbol = LayoutRoot.Resources["DrawFillSymbol"] as FillSymbol
            };

            MyDrawObject.DrawComplete += MyDrawObject_DrawComplete;
            MyDrawObject.DrawMode = DrawMode.None;
            MyDrawObject.IsEnabled = false;


        }

        /// <summary>
        /// Event handler for Draw Complete event of the draw object
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void MyDrawObject_DrawComplete(object sender, ESRI.ArcGIS.Client.DrawEventArgs args)
        {
            if (!MapLayersManager.Instance.annotationsLayerAdded && !MapLayersManager.Instance.onlineAnnotationLayersAdded) return;

            ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic()
            {
                Geometry = args.Geometry,
                Symbol = _activeSymbol,
            };

            if (MapLayersManager.Instance.annotationsLayerAdded)
            {
//                GraphicsLayer graphicsLayer = MapLayersManager.Instance.annotationsLayer as GraphicsLayer;
                GraphicsLayer graphicsLayer = MyMap.Layers["AnnotationsLayer"] as GraphicsLayer;
                graphicsLayer.Graphics.Add(graphic);
            }

            if (MapLayersManager.Instance.onlineAnnotationLayersAdded)
            {
                FeatureLayer fl;

                if (MyDrawObject.DrawMode == DrawMode.Point)
                {
                    fl = MyMap.Layers["PointAnnotationsLayer"] as FeatureLayer;
                }
                else if (MyDrawObject.DrawMode == DrawMode.Freehand || MyDrawObject.DrawMode == DrawMode.Polyline)
                {
                    fl = MyMap.Layers["LineAnnotationsLayer"] as FeatureLayer;
                }
                else if (MyDrawObject.DrawMode == DrawMode.Polygon || MyDrawObject.DrawMode == DrawMode.Triangle ||
                    MyDrawObject.DrawMode == DrawMode.Circle || MyDrawObject.DrawMode == DrawMode.Ellipse || MyDrawObject.DrawMode == DrawMode.Arrow)
                {
                    fl = MyMap.Layers["PolygonAnnotationsLayer"] as FeatureLayer;
                }
                else if (MyDrawObject.DrawMode == DrawMode.Rectangle) // Rectangles are returned the Draw object as Envelopes. We convert this to a polygon, to add to our feature layer.
                {
                    fl = MyMap.Layers["PolygonAnnotationsLayer"] as FeatureLayer;
                    Polygon polygon = new Polygon();
                    polygon.Rings.Add(GetPointCollectionFromEnvelope(graphic.Geometry as Envelope));
                    graphic.Geometry = polygon;
                }
                else
                    return;
                graphic.Geometry.SpatialReference = MyMap.SpatialReference;
                // Spatial reference is not set on some of the geometry Draw returns, or on the new rectangle polygon, and is required for addition to a feature layer.

                fl.Graphics.Add(graphic);
                fl.SaveEdits();
                MapLayersManager.Instance.UpdateAnnotationLayers();
            }

            

        }




        /// <summary>
        /// Utility function for adding rectangular polygons to the amp
        /// </summary>
        /// <returns></returns>
        private ESRI.ArcGIS.Client.Geometry.PointCollection GetPointCollectionFromEnvelope(Envelope env)
        {
            ESRI.ArcGIS.Client.Geometry.PointCollection pc = new ESRI.ArcGIS.Client.Geometry.PointCollection();
            pc.Add(new MapPoint(env.XMin, env.YMin));
            pc.Add(new MapPoint(env.XMin, env.YMax));
            pc.Add(new MapPoint(env.XMax, env.YMax));
            pc.Add(new MapPoint(env.XMax, env.YMin));
            pc.Add(new MapPoint(env.XMin, env.YMin));
            return pc;
        }

        /// <summary>
        /// Returns whether the map is in the draw mode
        /// </summary>
        /// <returns>Whether the draw mode is enabled or not</returns>
        public bool isMapInDrawMode()
        {
            if (MyDrawObject.DrawMode != DrawMode.None)
            {
                return true;
            }
            return false;
        }
         
        /// <summary>
        /// Returns whether the layers list is visible
        /// </summary>
        /// <returns></returns>
        public bool isLayersListVisible()
        {
            if (showLayersList) return true;

            return false;
        }

        /// <summary>
        /// Used to set the draw mode to point
        /// </summary>
        public void SetDrawPointMode()
        {
            MyDrawObject.DrawMode = DrawMode.Point;
            _activeSymbol = LayoutRoot.Resources["DefaultMarkerSymbol"] as Symbol;
            StartDrawing();
        }

        /// <summary>
        /// Used to set the draw mode to polyline
        /// </summary>
        public void SetDrawPolylineMode()
        {
            MyDrawObject.DrawMode = DrawMode.Polyline;
            _activeSymbol = LayoutRoot.Resources["DefaultLineSymbol"] as Symbol;
            StartDrawing();
        }

        /// <summary>
        /// Used to set the draw mode to polygon
        /// </summary>
        public void SetDrawPolygonMode()
        {
            MyDrawObject.DrawMode = DrawMode.Polygon;
            _activeSymbol = LayoutRoot.Resources["DefaultFillSymbol"] as Symbol;
            StartDrawing();
        }

        /// <summary>
        /// Used to set the draw mode to rectangle
        /// </summary>
        public void SetDrawRectangleMode()
        {
            MyDrawObject.DrawMode = DrawMode.Rectangle;
            _activeSymbol = LayoutRoot.Resources["DefaultFillSymbol"] as Symbol;
            StartDrawing();
        }

        /// <summary>
        /// Used to set the draw mode to free hand
        /// </summary>
        public void SetDrawFreehandMode()
        {
            MyDrawObject.DrawMode = DrawMode.Freehand;
            _activeSymbol = LayoutRoot.Resources["DefaultLineSymbol"] as Symbol;
            StartDrawing();
            
        }

        /// <summary>
        /// Clears the graphics that are drawn on the map
        /// </summary>
        public void ClearGraphics()
        {
            if (!MapLayersManager.Instance.annotationsLayerAdded && !MapLayersManager.Instance.onlineAnnotationLayersAdded) return;

            StopDrawing();

            if (MapLayersManager.Instance.annotationsLayerAdded)
            {
                //AnnotationMasterLayer graphicsLayer = MapLayersManager.Instance.annotationsLayer as AnnotationMasterLayer;
                GraphicsLayer graphicsLayer = MyMap.Layers["AnnotationsLayer"] as GraphicsLayer;
                graphicsLayer.Graphics.Clear();
            }

            if (MapLayersManager.Instance.onlineAnnotationLayersAdded)
            {
                MapLayersManager.Instance.pointAnnotationLayer.Graphics.Clear();
                MapLayersManager.Instance.lineAnnotationLayer.Graphics.Clear();
                MapLayersManager.Instance.polygonAnnotationLayer.Graphics.Clear();

                MapLayersManager.Instance.pointAnnotationLayer.SaveEdits();
                MapLayersManager.Instance.lineAnnotationLayer.SaveEdits();
                MapLayersManager.Instance.polygonAnnotationLayer.SaveEdits();

                MapLayersManager.Instance.UpdateAnnotationLayers();
            }
        }

        public void StartDrawing()
        {
            MyDrawObject.IsEnabled = true;

        }

        /// <summary>
        /// disabled the drawing mode
        /// </summary>
        public void StopDrawing()
        {
            MyDrawObject.DrawMode = DrawMode.None;
            MyDrawObject.IsEnabled = false;
        }        

        # endregion

        #region OtherMembers

        /// <summary>
        /// Refresh/Reload the map
        /// </summary>
        public void ReloadMap()
        {
            MyMap.UpdateLayout();
        }

        /// <summary>
        /// Gets image of the current view. This method is not used anymore.
        /// </summary>
        /// <returns></returns>
        private ImageSource ToImageSource()
        {
            FrameworkElement obj = this;

            // Save current canvas transform
            Transform transform = obj.LayoutTransform;
            obj.LayoutTransform = null;

            // fix margin offset as well
            Thickness margin = obj.Margin;
            obj.Margin = new Thickness(0, 0,
            margin.Right - margin.Left, margin.Bottom - margin.Top);

            // Get the size of canvas
            System.Windows.Size size = new System.Windows.Size(obj.ActualWidth, obj.ActualHeight);

            // force control to Update
            obj.Measure(size);
            obj.Arrange(new Rect(size));

            RenderTargetBitmap bmp = new RenderTargetBitmap(
            (int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);

            bmp.Render(obj);

            // return values as they were before
            obj.LayoutTransform = transform;
            obj.Margin = margin;

            return bmp;
        }

        public void RefreshAnnotationLayers()
        {
            FeatureLayer fl;

            fl = (MyMap.Layers["PointAnnotationsLayer"]) as FeatureLayer;        
            if (fl != null)
                fl.Update();

            fl = (MyMap.Layers["LineAnnotationsLayer"] as FeatureLayer);
            if (fl != null)
                fl.Update();

            fl = (MyMap.Layers["PolygonAnnotationsLayer"] as FeatureLayer);
            if (fl != null)
                fl.Update();
        }

        # endregion OtherMembers

        #region Bookmark pins
                
        
        /// <summary>
        /// Add a bookmark pin to the BookmarksLayer on the map. Works only if the BookmarksLayer is created and added to the map.
        /// </summary>
        /// <param name="pin">BookmarkPin to be added</param>
        public void AddBookmarkPin(BookmarkPin pin)
        {
            if (!MapLayersManager.Instance.bookmarkLayerAdded) return;

            GraphicsLayer graphicsLayer = MyMap.Layers["BookmarksLayer"] as GraphicsLayer;
            if (graphicsLayer == null) return;

            BookmarkPinGraphic graphic = new BookmarkPinGraphic();

            graphic.Geometry = new MapPoint(pin.Bookmark.MapCoordinate.X, pin.Bookmark.MapCoordinate.Y);
            if (pin.Priority == GISforTT_API.Bookmark.BookmarkPriority.High)
            {
                graphic.Symbol = LayoutRoot.Resources["HighPriorityPinSymbol"] as SimpleMarkerSymbol;
            }
            else if (pin.Priority == GISforTT_API.Bookmark.BookmarkPriority.Medium)
            {
                graphic.Symbol = LayoutRoot.Resources["MeduimPriorityPinSymbol"] as SimpleMarkerSymbol; 
            }
            else if (pin.Priority == GISforTT_API.Bookmark.BookmarkPriority.Low)
            {
                graphic.Symbol = LayoutRoot.Resources["LowPriorityPinSymbol"] as SimpleMarkerSymbol; 
            }

            /* Which mouse button event to listen for? */
            //graphic.MouseRightButtonDown += new MouseButtonEventHandler(graphic_MouseRightButtonDown);
            graphic.MouseLeftButtonDown += new MouseButtonEventHandler(graphic_MouseLeftButtonDown);
            
            BookmarkInfoTip mapTip = null;
            if (isBgMap)
            {
                mapTip = new BookmarkInfoTip(pin);
                /* prepare the MapTip in the background map but don't make it visible */
                mapTip.Visibility = Visibility.Collapsed;

                BackgroundMapLayer.Instance.AddMapTip(mapTip, pin.ScreenPt, 0.0);
            }
            else
            {
                mapTip = new BookmarkInfoTip(pin);
            }


            graphic.MapTip = mapTip;

            graphicsLayer.Graphics.Add(graphic);            
        }


        private void graphic_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var clickedPin = sender as BookmarkPinGraphic;
            var sel = clickedPin.Selected;

            var mapPoint = clickedPin.Geometry as MapPoint;
            Point scrPoint = Map.MapToScreen(mapPoint);

            var mapTip = clickedPin.MapTip as ScatterViewItem;
            mapTip.Center = scrPoint;

            mapTip.Visibility = Visibility.Visible;

            clickedPin.UnSelect();
        }

        private void graphic_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {

        }

        /// <summary>
        /// Used for demo purpose. Populates the background map with BookmarkPins representing the location of each Bookmark.
        /// </summary>
        public void CreateBookmarkPins(List<GISforTT_API.Bookmark> bmrks)
        {
            foreach (GISforTT_API.Bookmark tt in bmrks)
            {
                Point pt = Map.MapToScreen(tt.MapCoordinate);
                BookmarkPin ttpin = new BookmarkPin(tt, pt);
                AddBookmarkPin(ttpin);
            }
        }

        
        #endregion


        #region Map Layers Management


        /*public void AddMapLayer(Layer addLayer)
        {
            MyMap.Layers.Add(addLayer);
        }*/

        /// <summary>
        /// Look up a layer in the MapLayerManager to add to the map, used by MapLayersManager.AddLayer.
        /// To add your layer to all maps in the application, use MapLayersManager.AddLayer
        /// </summary>
        /// <param name="addLayer">Layer to be added to the map</param>
        public void AddMapLayer(String addLayerID)
        {
            Layer addLayer = MapLayersManager.Instance.Clonelayer(addLayerID);
            if (addLayer != null)
                MyMap.Layers.Add(addLayer);
        }

        /// <summary>
        /// Remove a layer from the map
        /// </summary>
        /// <param name="deleteLayer">Layer to be removed</param>
        /// <returns></returns>


        public void RemoveMapLayer(Layer deleteLayer)
        {
            LayerCollection layers = MyMap.Layers;

            foreach (Layer layer in layers)
            {
                if (layer.ID == deleteLayer.ID)
                {
                    MyMap.Layers.Remove(layer);
                    break;
                }
            }
        }

        #endregion



                
                
    }
}
